#pragma once

#include "Log.hpp"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <arpa/inet.h>
#include <string.h>
#include <string>
#include <functional>
#include "InetAddr.hpp"

using namespace LogModule;
using fun_t = std::function<std::string (const std::string& )>;
class UdpServer
{
    public:
    UdpServer(  int port , fun_t func)
        :_func(func)
        ,_port(port)
        ,_isrunning(false)

    {

    }

    void Init()
    {
        _sockfd = socket(AF_INET , SOCK_DGRAM , 0);
        if(_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket create failed" ;
            return ;
        }
        struct sockaddr_in local;
        bzero(&local , sizeof(local));
        local.sin_family = AF_INET;
        // local.sin_addr.s_addr = inet_addr(_ip.c_str());
        local.sin_addr.s_addr = INADDR_ANY;

        local.sin_port = htons(_port);
        int n = bind(_sockfd , (struct sockaddr*)&local , sizeof(local));
        if(n < 0)
        {
            LOG(LogLevel::FATAL) << "server bind failed";
            return ;
        }
        LOG(LogLevel::INFO) << "server bind success";

    }

    void Start()
    {
        _isrunning = true;
        while(_isrunning )
        {
            char buffer [1024];
            memset(buffer , 0 , sizeof(buffer));
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int rec_n = recvfrom(_sockfd , buffer , sizeof(buffer)-1, 0 , (struct sockaddr*)&peer , &len);
            if( rec_n < 0)
            {
                LOG(LogLevel::ERROR) << "server recvfrom failed";
                return;
            }
            LOG(LogLevel::INFO) << buffer ;
            // std::string sendmessage = "Server say# " ;
            // sendmessage += buffer;
            std::string result = _func(buffer);
            int send_n = sendto(_sockfd , result.c_str() , result.size() , 0 , (struct sockaddr*)&peer , sizeof(peer));
            if(send_n < 0)
            {
                LOG(LogLevel::ERROR) << "server sendto failed";
            }
            LOG(LogLevel::INFO) << "server sendto success";
        }
        return ;
    }
    private:
    int _sockfd;
    // std::string _ip;
    int _port;
    bool _isrunning;
    fun_t _func;
};